
#ifndef	LEVEL_PLAYER_HPP
#define	LEVEL_PLAYER_HPP

#include <physics/physics.hpp>
#include <drawables/animation.hpp>
#include <messenger/messenger.hpp>
#include <physics/user_data/user_data.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/array.hpp>

namespace player_state
{
	enum enum_
	{
		idle = 0,
		running,
		jumping,
		dying,

		number_of,
	};
};

namespace player_direction
{
	enum enum_
	{
		left = 0,
		right,

		number_of,
	};
};

class player
{
public:

	player( );
	void step( float delta_time );
	void draw( );
	player_state::enum_ state( ) const
	{
		return m_state;
	}

	size_t things( ) const
	{
		return m_things;
	}

	bool can_add_to_world( world_ptr world ) const
	{
		if ( m_upper_body == nullptr )
		{
			throw std::runtime_error( "erm... oops" );
		}

		return can_add_to_world( world, m_upper_body->GetPosition( ) );
	}

	bool can_add_to_world( world_ptr world, b2Vec2 const & position ) const;

	void add_to_world( world_ptr world )
	{
		if ( m_upper_body == nullptr )
		{
			throw std::runtime_error( "erm... oops" );
		}

		b2Vec2 position = m_upper_body->GetPosition( );
		add_to_world( world, position );
	}

	void add_to_world( world_ptr world, b2Vec2 const & position );

private:

	void switch_state( player_state::enum_ new_state );
	void switch_direction( player_direction::enum_ new_direction );
	void message_callback( std::string const & message_name, message_data_ptr data );
	bool is_in_air( );

	body_ptr m_upper_body;
	body_ptr m_lower_body;
	boost::shared_ptr< b2RevoluteJoint > m_revolute;

	size_t m_things;

	typedef boost::array< drawable_ptr, player_direction::number_of >		left_right_animation_t;
	typedef boost::array< left_right_animation_t, player_state::number_of >	state_animation_array_t;

	state_animation_array_t m_state_animations;
	player_direction::enum_ m_direction;
	player_state::enum_ m_state;

	float m_jump_held_for;
	bool m_falling;
	float m_has_been_dead_for;

	float m_time;
	float m_time_last_touched_floor;
	float m_hacky_jump_timer;

	boost::signals2::scoped_connection m_messenger_connection;
	boost::scoped_ptr< base_user_data > m_upper_user_data;

	sf::Sound m_pickup_sound;
	sf::Sound m_jump_sound;
	sf::Sound m_landed_sound;
	sf::Sound m_death_sound;
};

#endif	//LEVEL_PLAYER_HPP
